package com.xbongbong.paas.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.XbbResponse;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.XbbProConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.scriptQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author kaka
 * @time 2018-9-5 15:12
 */
@RestController
@RequestMapping(XbbProConstant.API_ROOT_PREFIX + "/esDemo")
public class ElasticSearchDemoController {

    private static final Logger LOG = LoggerFactory.getLogger(ElasticSearchDemoController.class);
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;


    @RequestMapping(value = "/script", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String script(@RequestBody @Valid BaseDTO feedbackDTO, BindingResult br) {
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                Script script = new Script("doc['data.num_4'].value - doc['data.num_1'].value > 0");
                boolQueryBuilder.filter(scriptQuery(script));
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER;
                boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
                SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
                SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
                sourceBuilder.query(boolQueryBuilder);
                searchRequest.source(sourceBuilder);
                XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
                response = new XbbResponse<>("");
            } catch (Exception e) {
                response = new XbbResponse<>("");
            }
        }
        return JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping(value = "/scriptAgg", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String scriptAgg(@RequestBody @Valid BaseDTO feedbackDTO, BindingResult br) {
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
//        boolQueryBuilder.filter(termQuery("corpid.keyword", "1"));
                Script script = new Script("doc['data.num_4'].value - doc['data.num_1'].value > 0");
                TermsAggregationBuilder termsAggregation = AggregationBuilders.terms("aggs01").field("formId").order(BucketOrder.count(false));
                boolQueryBuilder.filter(scriptQuery(script));
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER;
                boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
                SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
                SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                sourceBuilder.aggregation(termsAggregation);
                PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
                sourceBuilder.query(boolQueryBuilder);
                searchRequest.source(sourceBuilder);
                XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
                response = new XbbResponse<>("");
            } catch (Exception e) {
                response = new XbbResponse<>("");
            }
        }
        return JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping(value = "/buckSize", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String buckSize(@RequestBody @Valid BaseDTO feedbackDTO, BindingResult br) {
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery("corpid.keyword","1"));
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER;
                boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
                SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
                SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
                sourceBuilder.query(boolQueryBuilder);
                searchRequest.source(sourceBuilder);
                XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
                response = new XbbResponse<>("");
            } catch (Exception e) {
                response = new XbbResponse<>("");
            }
        }
        return JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping(value = "/count", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String count(@RequestBody @Valid BaseDTO feedbackDTO, BindingResult br) {
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery("corpid.keyword","1"));
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER;
                CountRequest countRequest = new CountRequest(indexTypeEnum.getIndex());
                countRequest.query(boolQueryBuilder);
                long count  = xbbElasticsearchRestTemplate.count(countRequest);
                response = new XbbResponse<>("");
            } catch (Exception e) {
                response = new XbbResponse<>("");
            }
        }
        return JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping(value = "/agg", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String agg(@RequestBody @Valid BaseDTO feedbackDTO, BindingResult br) {
        XbbResponse<String> response;
        if (br.hasErrors()) {
            String errMsg = Objects.requireNonNull(br.getFieldError()).getDefaultMessage();
            response = new XbbResponse<>(SystemErrorCodeEnum.API_ERROR_100002, errMsg);
        } else {
            try {
                TermsAggregationBuilder termsAggregation = AggregationBuilders.terms("aggs01").field("id").order(BucketOrder.count(false)).size(SizeConstant.TERM_AGG_MAX_BUCKETS);
                IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CUSTOMER;
                SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
                SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                sourceBuilder.aggregation(termsAggregation);
                searchRequest.source(sourceBuilder);
                JSONObject jsonObject = xbbElasticsearchRestTemplate.getAggResponseJson(searchRequest);
                response = new XbbResponse<>("");
            } catch (Exception e) {
                response = new XbbResponse<>("");
            }
        }
        return JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
    }

    @RequestMapping(value = "/shareList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String shareList(@RequestBody @Valid BaseDTO baseDTO, BindingResult br) {
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CLUE;
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = boolQuery();

        // 基础公共条件
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "pihuazhenduo"));
        boolQueryBuilder.filter(termQuery(StringConstant.FORM_ID, 46849));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        for (int i = 1018; i > 0; i--) {
            boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        }
        boolQueryBuilder.filter(termsQuery(StringConstant.FLOW_STATUS, Arrays.asList(0,2)));
        List<Integer> list = new ArrayList<>();
        for (int i = 1024; i> 0; i--) {
            list.add(i);
        }
        boolQueryBuilder.filter(termsQuery(StringConstant.FLOW_STATUS, list));


//        Script script = new Script("doc['data.num_4'].value - doc['data.num_1'].value > 0");
//        boolQueryBuilder.filter(scriptQuery(script));
//        boolQueryBuilder.mustNot();


        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));

        // should
        BoolQueryBuilder should = boolQuery();

        // 基础团队条件
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "pihuazhenduo"));
        teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        teamQueryBuilder.filter(termQuery("data.text_1", "pi001"));
        teamQueryBuilder.filter(termQuery("data.num_2", 1));

        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_CLUE_TEAM.getType(), teamQueryBuilder, ScoreMode.Max);

        // 一组共享
        BoolQueryBuilder shareBool = boolQuery();

        // 共享条件
        BoolQueryBuilder conditionsBool1 = boolQuery();

        // 多个条件，条件组内且，组之间或
        BoolQueryBuilder conditionBool1 = boolQuery();
        conditionBool1.filter(termQuery("data.text_1", "爱我你就哦发挥额"));
        conditionBool1.filter(termQuery("data.text_5", "2"));

        BoolQueryBuilder conditionBool2 = boolQuery();
        conditionBool2.filter(termQuery("data.text_1", "asdfdsf的粉丝6"));
        conditionBool2.filter(termQuery("data.text_5", "1"));

        BoolQueryBuilder conditionBool3 = boolQuery();
        conditionBool3.filter(termQuery("data.text_1", "asdfdsf的粉丝3"));
        conditionBool3.filter(termQuery("data.text_5", "1"));


        conditionsBool1.should(conditionBool1);
        conditionsBool1.should(conditionBool2);
        conditionsBool1.should(conditionBool3);
        conditionsBool1.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);

        // 共享团队
        BoolQueryBuilder shareTeamBool = boolQuery();
        shareTeamBool.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "pihuazhenduo"));
        shareTeamBool.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        shareTeamBool.filter(termQuery("data.text_1", "pi001"));
        shareTeamBool.filter(termQuery("data.num_2", 1));

        HasChildQueryBuilder shareTeamHasChild = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_CLUE_TEAM.getType(), shareTeamBool, ScoreMode.Max);

        conditionsBool1.filter(shareTeamHasChild);


        // 团队
        should.should(hasChildQueryBuilder);
        // 共享条件
        for (int i = 1023; i > 0; i--) {
            should.should(conditionsBool1);
        }


        should.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        boolQueryBuilder.filter(should);


        // 排序
        sourceBuilder.sort(new FieldSortBuilder("updateTime").order(SortOrder.DESC));
        sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.DESC));
        sourceBuilder.query(boolQueryBuilder);

        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 20);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);

        try {
            XbbAggregatedPage<ClueEntityExt> clueEntityExtXbbAggregatedPage = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
            List<ClueEntityExt> content = clueEntityExtXbbAggregatedPage.getContent();
            long totalElements = clueEntityExtXbbAggregatedPage.getTotalElements();
            LOG.error("totalElements:{}", totalElements);
        } catch (XbbException e) {
            LOG.error("---------test", e);
        }


        return JSON.toJSONString(searchRequest.source());
    }

    @RequestMapping(value = "/shareTestList", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public String shareTestList(@RequestBody @Valid BaseDTO baseDTO, BindingResult br) {
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_CLUE;
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = boolQuery();

        // 基础公共条件
        boolQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "ding805e6804e12da7e0"));
        boolQueryBuilder.filter(termQuery(StringConstant.FORM_ID, 46849));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
//        for (int i = 1018; i > 0; i--) {
//            boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
//        }
        boolQueryBuilder.filter(termsQuery(StringConstant.FLOW_STATUS, Arrays.asList(0,2)));
//        List<Integer> list = new ArrayList<>();
//        for (int i = 1024; i> 0; i--) {
//            list.add(i);
//        }
//        boolQueryBuilder.filter(termsQuery(StringConstant.FLOW_STATUS, list));


//        Script script = new Script("doc['data.num_4'].value - doc['data.num_1'].value > 0");
//        boolQueryBuilder.filter(scriptQuery(script));
//        boolQueryBuilder.mustNot();


        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));

        // should
        BoolQueryBuilder should = boolQuery();

        // 基础团队条件
        BoolQueryBuilder teamQueryBuilder = boolQuery();
        teamQueryBuilder.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "ding805e6804e12da7e0"));
        teamQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        teamQueryBuilder.filter(termQuery("data.text_1", "16480851444329040"));
        teamQueryBuilder.filter(termQuery("data.num_2", 1));

        HasChildQueryBuilder hasChildQueryBuilder = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_CLUE_TEAM.getType(), teamQueryBuilder, ScoreMode.Max);

        // 一组共享
        BoolQueryBuilder shareBool = boolQuery();

        // 共享条件
        BoolQueryBuilder conditionsBool1 = boolQuery();

        // 多个条件，条件组内且，组之间或
        BoolQueryBuilder conditionBool1 = boolQuery();
        conditionBool1.filter(termQuery("data.num_3", 2));
        conditionBool1.filter(termQuery("data.text_5", "3"));
        conditionBool1.filter(termQuery("data.num_2", 0));
        conditionBool1.filter(termQuery("data.num_2", 0));
        conditionBool1.filter(termQuery("data.num_2", 0));
//
//        BoolQueryBuilder conditionBool2 = boolQuery();
//        conditionBool2.filter(termQuery("data.num_3", 2));
//        conditionBool2.filter(termQuery("data.text_5", "3"));
//        conditionBool2.filter(termQuery("data.num_2", 0));
//        conditionBool2.filter(termQuery("data.num_2", 0));
//        conditionBool2.filter(termQuery("data.num_2", 0));
//
//        BoolQueryBuilder conditionBool3 = boolQuery();
//        conditionBool3.filter(termQuery("data.text_1", "asdfdsf的粉丝3"));
//        conditionBool3.filter(termQuery("data.text_5", "1"));


        for (int i = 5; i > 0; i--) {
            conditionsBool1.should(conditionBool1);
        }
//        conditionsBool1.should(conditionBool2);
//        conditionsBool1.should(conditionBool3);
        conditionsBool1.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);

        // 共享团队
        BoolQueryBuilder shareTeamBool = boolQuery();
        shareTeamBool.filter(termQuery(StringConstant.CORPID + StringConstant.POINT+ StringConstant.KEY_WORD, "ding805e6804e12da7e0"));
        shareTeamBool.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
        shareTeamBool.filter(termQuery("data.text_1", "16480851444329040"));
        shareTeamBool.filter(termQuery("data.num_2", 1));

        HasChildQueryBuilder shareTeamHasChild = JoinQueryBuilders.hasChildQuery(IndexTypeEnum.IDX_SAAS_CLUE_TEAM.getType(), shareTeamBool, ScoreMode.Max);

        conditionsBool1.filter(shareTeamHasChild);


        // 团队
        should.should(hasChildQueryBuilder);
        // 共享条件
        for (int i = 10; i > 0; i--) {
            should.should(conditionsBool1);
        }


        should.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
        boolQueryBuilder.filter(should);


        // 排序
        sourceBuilder.sort(new FieldSortBuilder("updateTime").order(SortOrder.DESC));
        sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.DESC));
        sourceBuilder.query(boolQueryBuilder);

        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 20);
        SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
        searchRequest.source(sourceBuilder);

        try {
            XbbAggregatedPage<ClueEntityExt> clueEntityExtXbbAggregatedPage = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ClueEntityExt.class);
            List<ClueEntityExt> content = clueEntityExtXbbAggregatedPage.getContent();
            long totalElements = clueEntityExtXbbAggregatedPage.getTotalElements();
            LOG.error("totalElements:{}", totalElements);
        } catch (XbbException e) {
            LOG.error("---------test", e);
        }


        return JSON.toJSONString(searchRequest.source());
    }

}